package cn.funeralobjects.ams.service.impl;

import cn.funeralobjects.ams.entity.EAccess;
import cn.funeralobjects.ams.entity.EAccessKey;
import cn.funeralobjects.ams.model.AccessKey;
import cn.funeralobjects.ams.repository.EAccessKeyRepository;
import cn.funeralobjects.ams.repository.EAccessRepository;
import cn.funeralobjects.ams.service.AccessKeyService;
import cn.funeralobjects.common.jpa.service.*;
import cn.funeralobjects.common.repository.*;
import cn.funeralobjects.common.service.annotataion.CommonRollback;
import cn.funeralobjects.common.service.annotataion.CommonService;
import cn.funeralobjects.common.service.exception.DataConflictException;
import cn.funeralobjects.common.service.exception.LackDataException;
import cn.funeralobjects.common.service.validate.DataCheck;
import cn.funeralobjects.util.Assert;
import cn.funeralobjects.util.NumberUtils;
import cn.funeralobjects.util.annotation.ArgNotZero;
import cn.funeralobjects.util.annotation.AssertArg;
import org.springframework.data.repository.CrudRepository;

import javax.annotation.Resource;
import java.util.Optional;

/**
 * Implement of AccessService
 *
 * @author FuneralObjects
 * Create date: 2020/5/25 2:56 PM
 */
@CommonService
public class AccessKeyServiceImpl implements AccessKeyService,
        JpaCodeService<EAccess, Integer>,
        JpaEntityService<EAccess, Integer>,
        JpaNameService<EAccess, Integer>,
        JpaCommitService<Integer>,
        JpaEnableService<EAccess, Integer>,
        JpaDelSaltService<EAccess, Integer>,
        JpaModifyService<AccessKey, EAccessKey, Integer> {

    @Resource
    private EAccessRepository eAccessRepository;
    @Resource
    private EAccessKeyRepository eAccessKeyRepository;

    @CommonRollback
    @Override
    public EAccessKey add(AccessKey accessKey) {
        this.validateModify(accessKey);
        this.checkConflict(accessKey);
        EAccessKey eAccessKey = this.toEntity(accessKey);
        EAccess eAccess = new EAccess();
        eAccess.setCode(accessKey.getAccess().getCode())
                .setName(accessKey.getAccess().getName());
        eAccess = eAccessRepository.save(eAccess);
        eAccessKey.setAccessId(eAccess.getId());
        return eAccessKeyRepository.save(eAccessKey);
    }

    @CommonRollback
    @Override
    public void update(Integer id, AccessKey accessKey) {
        this.validateModify(accessKey);
        this.validateId(id);
        this.checkConflict(accessKey, id);
        EAccess eAccess = eAccessRepository.findById(id).orElseThrow(() -> new LackDataException(String.format("The AccessKey[%s] doesn't exists!", id), this.createDataCode("id", String.valueOf(id))));
        EAccessKey eAccessKey = eAccessKeyRepository.findById(id).orElseThrow(() -> new LackDataException(String.format("The AccessKey[%s] doesn't exists!", id), this.createDataCode("id", String.valueOf(id))));
        this.copyToEntity(accessKey, eAccessKey);
        eAccess.setCode(accessKey.getAccess().getCode());
        eAccess.setName(accessKey.getAccess().getName());
    }

    @Override
    @AssertArg
    public void checkConflict(@AssertArg AccessKey accessKey) throws DataConflictException {
        DataCheck.conflictData(this.existsByName(accessKey.getAccess().getName()), () -> createDataCode("name", accessKey.getAccess().getName()));
    }

    @Override
    public EAccessKey toEntity(AccessKey accessKey) {
        return Optional.ofNullable(accessKey)
                .map(modify -> {
                    EAccess access = new EAccess();
                    access.setCode(modify.getAccess().getCode())
                            .setName(modify.getAccess().getName());
                    return new EAccessKey()
                            .setStatus(modify.getStatus())
                            .setAccessKeySecret(modify.getAccessKeySecret())
                            .setAccessKeyId(modify.getAccessKeyId());
                }).orElse(null);
    }

    @Override
    public CodeRepository<EAccess, Integer> codeRepository() {
        return eAccessRepository;
    }

    @Override
    public CommitRepository<Integer> commitRepository() {
        return eAccessRepository;
    }

    @Override
    public DelSaltRepository<EAccess, Integer> delSaltRepository() {
        return eAccessRepository;
    }

    @Override
    public EnableRepository<EAccess, Integer> enableRepository() {
        return eAccessRepository;
    }

    @Override
    public EntityRepository<EAccess, Integer> entityRepository() {
        return eAccessRepository;
    }

    @Override
    public CrudRepository<EAccessKey, Integer> modifyRepository() {
        return eAccessKeyRepository;
    }

    @Override
    public NameRepository<EAccess, Integer> nameRepository() {
        return eAccessRepository;
    }

    @Override
    @AssertArg
    public void checkConflict(@AssertArg AccessKey accessKey, @ArgNotZero Integer withoutId) throws DataConflictException {
        DataCheck.conflictData(this.existsByName(accessKey.getAccess().getName(), withoutId), () -> createDataCode("name", accessKey.getAccess().getName()));
    }

    @Override
    public void copyToEntity(AccessKey sourceModify, EAccessKey targetEntity) {
        targetEntity.setAccessKeyId(sourceModify.getAccessKeyId())
                .setStatus(sourceModify.getStatus())
                .setLastCheck(targetEntity.getLastCheck())
                .setAccessKeySecret(sourceModify.getAccessKeySecret());
    }

    @Override
    public boolean isValid(Integer id) {
        return NumberUtils.notZero(id);
    }

    @Override
    public void validateModify(AccessKey accessKey) {
        Assert.argAssert(accessKey, "accessKey");
    }

    @Override
    public Integer getExistsDelSalt() {
        return (Integer) eAccessRepository.getDefaultExistsDelSalt();
    }
}
